import backtrader as bt

class PrintClose(bt.Strategy):

    def log(self, txt, dt=None):
        dt = dt or self.datas[0].datetime.date(0)
        print('%s, %s' % (dt.isoformat(), txt))
        #打印日期和收盘价格

    def __init__(self):
        #引用data[0]中的收盘价格数据
        self.dataclose = self.datas[0].close

    def next(self):
        #将收盘价保留两位小数再输出
        self.log('Close: %.2f' % self.dataclose[0])

class MAcrossover(bt.Strategy): 
    #移动平均参数
    params = (('pfast',7),('pslow',92),)

    def log(self, txt, dt=None):
        dt = dt or self.datas[0].datetime.date(0)
        # print('%s, %s' % (dt.isoformat(), txt))  # 执行策略优化时 可注释掉此行

    def __init__(self):
        self.dataclose = self.datas[0].close
        # Order变量包含持仓数据与状态
        self.order = None
        # 初始化移动平均数据
        self.slow_sma = bt.indicators.MovingAverageSimple(self.datas[0], period=self.params.pslow)
        self.fast_sma = bt.indicators.MovingAverageSimple(self.datas[0], period=self.params.pfast)
        ''' 使用内置的交叉判断工具
        self.crossover = bt.indicators.CrossOver(self.slow_sma, self.fast_sma)'''


    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # 主动买卖的订单提交或接受时  - 不触发
            return

        # 验证订单是否完成
        # 注意: 当现金不足时，券商可以拒绝订单
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log('BUY EXECUTED, %.2f' % order.executed.price)
            elif order.issell():
                self.log('SELL EXECUTED, %.2f' % order.executed.price)
            self.bar_executed = len(self)

        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')

        # 重置订单
        self.order = None

    def next(self):
        ''' Logic for using the built-in crossover indicator

        if self.crossover > 0: # Fast ma crosses above slow ma
            pass # Signal for buy order
        elif self.crossover < 0: # Fast ma crosses below slow ma
            pass # Signal for sell order
        '''

        # 检测是否有未完成订单
        if self.order:
            return

        # 验证是否有持仓
        if not self.position:
            # 如果没有持仓，寻找开仓信号

            # SMA快线突破SMA慢线
            if self.fast_sma[0] > self.slow_sma[0] and self.fast_sma[-1] < self.slow_sma[-1]:
                self.log('BUY CREATE, %.2f' % self.dataclose[0])
                #继续追踪已经创建的订单，避免重复开仓
                self.order = self.buy()

            # SMA快线跌破SMA慢线
            elif self.fast_sma[0] < self.slow_sma[0] and self.fast_sma[-1] > self.slow_sma[-1]:
                self.log('SELL CREATE, %.2f' % self.dataclose[0])
                #继续追踪已经创建的订单，避免重复开仓
                self.order = self.sell()
        else:
            # 如果已有持仓，寻找平仓信号
            if len(self) >= (self.bar_executed + 5):
                self.log('CLOSE CREATE, %.2f' % self.dataclose[0])
                self.order = self.close()

class Screener_SMA(bt.Analyzer):
    params = (('period',20), ('devfactor',2),)

    def start(self):
        self.bbands = {data: bt.indicators.BollingerBands(data, period=self.params.period, devfactor=self.params.devfactor)
                     for data in self.datas}


    def stop(self):
        self.rets['over'] = list()
        self.rets['under'] = list()

        for data, band in self.bbands.items():
            node = data._name, data.close[0], round(band.lines.bot[0], 2)
            if data > band.lines.bot:
                self.rets['over'].append(node)
            else:
                self.rets['under'].append(node)

class MyIndicator(bt.Strategy):

    def log(self, txt, dt=None):
        dt = dt or self.datas[0].datetime.date(0)
        print('%s, %s' % (dt.isoformat(), txt)) #打印收盘价格和日期
        
    def __init__(self):
        #Keep a reference to the "close" line in the data[0] dataseries
        self.dataclose = self.datas[0].close
        self.datahigh = self.datas[0].high
        self.datalow = self.datas[0].low
        
    def next(self):
        day_range_total = 0
        for i in range(-13, 1):
            day_range = self.datahigh[i] - self.datalow[i]
            day_range_total += day_range
        M_Indicator = day_range_total / 14

        self.log('Close: %.2f, M_Indicator: %.4f' % (self.dataclose[0], M_Indicator))


class BtcSentiment(bt.Strategy):
    params = (('period', 10), ('devfactor', 1),)

    def log(self, txt, dt=None):
        dt = dt or self.datas[0].datetime.date(0)
        print('%s, %s' % (dt.isoformat(), txt))

    def __init__(self):
        self.btc_price = self.datas[0].close
        self.google_sentiment = self.datas[1].close
        self.bbands = bt.indicators.BollingerBands(self.google_sentiment, period=self.params.period,
                                                   devfactor=self.params.devfactor)

        self.order = None

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            return

        if order.status in [order.Completed]:
            if order.isbuy():
                self.log('BUY EXECUTED, %.2f' % order.executed.price)
            elif order.issell():
                self.log('SELL EXECUTED, %.2f' % order.executed.price)
            self.bar_executed = len(self)

        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')

        self.order = None

    def next(self):
        # 检查是否有正在执行的订单
        if self.order:
            return

        # 看多信号
        if self.google_sentiment > self.bbands.lines.top[0]:
            # 检查是否有持仓
            if not self.position:
                self.log('Google Sentiment Value: %.2f' % self.google_sentiment[0])
                self.log('Top band: %.2f' % self.bbands.lines.top[0])
                # 没有持仓则开仓多头
                self.log('***BUY CREATE, %.2f' % self.btc_price[0])
                # 追踪订单避免重复开仓
                self.order = self.buy()

                # 看空信号
        elif self.google_sentiment < self.bbands.lines.bot[0]:
            # 检查是否有持仓
            if not self.position:
                self.log('Google Sentiment Value: %.2f' % self.google_sentiment[0])
                self.log('Bottom band: %.2f' % self.bbands.lines.bot[0])
                # 没有持仓则开仓空头
                self.log('***SELL CREATE, %.2f' % self.btc_price[0])
                # 追踪订单避免重复开仓
                self.order = self.sell()

        # 中性信号，对既有仓位平仓
        else:
            if self.position:
                # 如果有仓位，则平仓
                self.log('Google Sentiment Value: %.2f' % self.google_sentiment[0])
                self.log('Bottom band: %.2f' % self.bbands.lines.bot[0])
                self.log('Top band: %.2f' % self.bbands.lines.top[0])
                self.log('CLOSE CREATE, %.2f' % self.btc_price[0])
                self.order = self.close()